package com.whut.service.impl;

import com.whut.dao.AsyncOpenStackRestDao;
import com.whut.dao.OpenStackRestDao;
import com.whut.domain.OpenStackUserQuota;
import com.whut.domain.User;
import com.whut.domain.Vhost;
import com.whut.service.OpenStackService;
import com.whut.service.QuotaService;
import com.whut.service.UserService;
import com.whut.service.VHostService;
import com.whut.util.TimeFormatUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Logger;

/**
 * Created by YY on 2018-01-29.
 */
@Service
public class OpenStackServiceImpl implements OpenStackService{


    private static final Logger logger=Logger.getLogger(String.valueOf(OpenStackServiceImpl.class));
    @Autowired
    private QuotaService quotaService; //配额表
    @Autowired
    private VHostService vHostService; //虚拟机表
    @Autowired
    private UserService userService;//用户表
    @Autowired
    private OpenStackRestDao openStackRestDao;//rest接口
    @Autowired
    private AsyncOpenStackRestDao asyncOpenStackRestDao;//异步rest接口


    @Override
    public void setOpenStackUserQuota(String username,String maxInstance, String maxCpu, String maxRam, String maxDisk,
                               String currentInstance,String currentCpu,String currentRam,String currentDisk){
        OpenStackUserQuota quota=new OpenStackUserQuota(username,maxInstance,maxCpu,maxRam,maxDisk,
                currentInstance,currentCpu,currentRam,currentDisk);
        quotaService.insertQuota(quota);
    }

    @Override
    public boolean updateOpenStackUserCurrentQuota(String username, boolean isAdd, String instance, String cpu, String ram, String disk) {
        OpenStackUserQuota quota = quotaService.selectQuotaByUserName(username);
        if(isAdd){
            quota.setCurrentinstance(String.valueOf(Integer.parseInt(quota.getCurrentinstance())+ Integer.parseInt(instance)));
            quota.setCurrentcpu(String.valueOf(Integer.parseInt(quota.getCurrentcpu())+ Integer.parseInt(cpu)));
            quota.setCurrentram(String.valueOf(Integer.parseInt(quota.getCurrentram())+ Integer.parseInt(ram)));
            quota.setCurrentdisk(String.valueOf(Integer.parseInt(quota.getCurrentdisk())+ Integer.parseInt(disk)));
            quotaService.updateQuota(username,quota);
            return true;
        }else {
            int newCurrentInstance=Integer.parseInt(quota.getCurrentinstance())- Integer.parseInt(instance);
            int newCurrentCpu=Integer.parseInt(quota.getCurrentcpu())- Integer.parseInt(cpu);
            int newCurrentRam=Integer.parseInt(quota.getCurrentram())- Integer.parseInt(ram);
            int newCurrentDisk=Integer.parseInt(quota.getCurrentdisk())- Integer.parseInt(disk);
            if(newCurrentInstance>=0&&newCurrentCpu>=0&&newCurrentRam>=0&&newCurrentDisk>=0){
                quota.setCurrentinstance(String.valueOf(newCurrentInstance));
                quota.setCurrentcpu(String.valueOf(newCurrentCpu));
                quota.setCurrentram(String.valueOf(newCurrentRam));
                quota.setCurrentdisk(String.valueOf(newCurrentDisk));
                quotaService.updateQuota(username,quota);
                return true;
            }
           return false;
        }
    }

    @Override
    public boolean updateOpenStackUserMaxQuota(String username, boolean isAdd, String instance, String cpu, String ram, String disk) {
        OpenStackUserQuota quota = quotaService.selectQuotaByUserName(username);
        if(isAdd){
            quota.setMaxinstance(String.valueOf(Integer.parseInt(quota.getMaxinstance())+ Integer.parseInt(instance)));
            quota.setMaxcpu(String.valueOf(Integer.parseInt(quota.getMaxcpu())+ Integer.parseInt(cpu)));
            quota.setMaxram(String.valueOf(Integer.parseInt(quota.getMaxram())+ Integer.parseInt(ram)));
            quota.setMaxdisk(String.valueOf(Integer.parseInt(quota.getMaxdisk())+ Integer.parseInt(disk)));
            quotaService.updateQuota(username,quota);
            return true;
        }else {
            int newMaxInstance = Integer.parseInt(quota.getMaxinstance()) - Integer.parseInt(instance);
            int newMaxCpu = Integer.parseInt(quota.getMaxcpu()) - Integer.parseInt(cpu);
            int newMaxRam = Integer.parseInt(quota.getMaxram()) - Integer.parseInt(ram);
            int newMaxDisk = Integer.parseInt(quota.getMaxdisk()) - Integer.parseInt(disk);
            int currentInstance = Integer.parseInt(quota.getCurrentinstance());
            int currentCpu = Integer.parseInt(quota.getCurrentcpu());
            int currentRam = Integer.parseInt(quota.getCurrentram());
            int currentDisk = Integer.parseInt(quota.getCurrentdisk());
            if (newMaxInstance >= currentInstance && newMaxCpu >= currentCpu && newMaxRam >= currentRam && newMaxDisk >= currentDisk) {
                quota.setMaxinstance(String.valueOf(newMaxInstance));
                quota.setMaxcpu(String.valueOf(newMaxCpu));
                quota.setMaxram(String.valueOf(newMaxRam));
                quota.setMaxdisk(String.valueOf(newMaxDisk));
                quotaService.updateQuota(username,quota);
                return true;
            }
            return false;
        }
    }

    @Override
    public Map<String,String> getLeftoverQuota(String username) {
        Map<String,String> map =new TreeMap<>();
        OpenStackUserQuota quota = quotaService.selectQuotaByUserName(username);
        if(quota!=null){
            map.put("instance",String.valueOf(Integer.parseInt(quota.getMaxinstance())-Integer.parseInt(quota.getCurrentinstance())));
            map.put("vcpu",String.valueOf(Integer.parseInt(quota.getMaxcpu())-Integer.parseInt(quota.getCurrentcpu())));
            map.put("ram",String.valueOf(Integer.parseInt(quota.getMaxram())-Integer.parseInt(quota.getCurrentram())));
            map.put("disk",String.valueOf(Integer.parseInt(quota.getMaxdisk())-Integer.parseInt(quota.getCurrentdisk())));
        }
        return map;
    }

    @Override
    public boolean checkCanCreate(String username, String useInstance,String useCpu, String useRam, String useDisk) {
        Map<String,String> map = getLeftoverQuota(username);
        return  map!=null&&
                (Integer.parseInt(map.get("instance"))>=Integer.parseInt(useInstance))&&
                (Integer.parseInt(map.get("vcpu"))>=Integer.parseInt(useCpu))&&
                (Integer.parseInt(map.get("ram"))>=Integer.parseInt(useRam))&&
                (Integer.parseInt(map.get("disk"))>=Integer.parseInt(useDisk));
    }

    @Override
    public List<String> getVirtualMachineCurrentAvailableOptions (String hostID) {
        List<String> list =new ArrayList<>();
        Vhost vhost= vHostService.selectVhostByHostId(hostID);
        if(vhost==null){
            return list;
        }
        String isLocked = vhost.getIslocked();
        if(isLocked.equals("true")){
            list.add("unlock");
            return list;
        }
        String status = vhost.getStatus();
        switch (status){
            case "SHUTDOWN":{
                list.add("start");
                list.add("lock");
                list.add("delete");
            }break;
            case "SUSPENDED":{
                list.add("resume");
                list.add("lock");
                list.add("delete");
            }break;
            case "PAUSED":{
                list.add("unpaused");
                list.add("lock");
                list.add("delete");
            }
            case "ACTIVE":{
                list.add("stop");
                list.add("reboot");
                list.add("suspend");
                list.add("pause");
                list.add("lock");
                list.add("delete");
            }break;
            default:
                break;
        }
        return list;
    }

    @Override
    public List<Integer> getVirtualMachineCurrentAvailableOptionsCode(String hostId) {
        List<Integer> list =new ArrayList<>();
        Vhost vhost= vHostService.selectVhostByHostId(hostId);
        if(vhost==null){
            return list;
        }
        String isLocked = vhost.getIslocked();
        if(isLocked.equals("true")){
            list.add(9);
            return list;
        }
        String status = vhost.getStatus();
        switch (status){
            case "SHUTDOWN":{
                list.add(1);
                list.add(8);
                list.add(0);
            }break;
            case "SUSPENDED":{
                list.add(5);
                list.add(8);
                list.add(0);
            }break;
            case "PAUSED":{
                list.add(7);
                list.add(8);
                list.add(0);
            }
            case "ACTIVE":{
                list.add(2);
                list.add(3);
                list.add(4);
                list.add(6);
                list.add(8);
                list.add(0);
            }break;
            default:
                break;
        }
        return list;
    }

    @Override
    public boolean registerOpenStackUser(String username, String password) {
        return openStackRestDao.registerOpenStackUser(username,password);
    }

    @Override
    public boolean removeOpenStackUser(String username, String password) {
        if(openStackRestDao.removeOpenStackUser(username,password)){
            userService.deleteUser(username);
            quotaService.deleteQuotaByUserName(username);
            return true;
        }
        return false;
    }

    //只是创建，并返回创建有没有成功，并不返回虚拟机信息
    @Override
    public boolean createVirtualMachine(String username, String password, String virtualMachineName,
                                        String image, String cpu, String ram, String disk) {
        if(!checkCanCreate(username,"1",cpu,ram,disk)){
            return false;
        }
        if(openStackRestDao.createVirtualMachine(username,password,virtualMachineName,image,cpu,ram,disk)){
            vHostService.insertVhost(new Vhost(username,virtualMachineName,image,cpu,ram,disk,TimeFormatUtil.getCurrentTime(),"false"));
            updateOpenStackUserCurrentQuota(username,true,"1",cpu,ram,disk);
            return true;
        }
        return false;
    }

    @Override
    public Map<String, String> createVMAndAsyncGetInfo(String username, String password, String virtualMachineName, String image, String cpu, String ram, String disk) {
        Map<String,String> map =new TreeMap<>();
        map.put("event","create");//告诉前台这是创建虚拟机事件
        if(!checkCanCreate(username,"1",cpu,ram,disk)){
            map.put("result","配额用尽");
            return map;
        }
        if(openStackRestDao.createVirtualMachine(username,password,virtualMachineName,image,cpu,ram,disk)){
            Future<Map<String, String>> task1 = asyncOpenStackRestDao.getVirtualMachineConsoleUrl(username, password, virtualMachineName);
            Future<Map<String, String>> task2 = asyncOpenStackRestDao.getVirtualMachineStatus(username, password, virtualMachineName);
            String currentTime =TimeFormatUtil.getCurrentTime();
            map.put("instance",virtualMachineName);
            map.put("instance_time",currentTime);
            map.put("image",image);
            map.put("islocked","false");
            while (true) {
                if (task1.isDone() && task2.isDone()) {
                    break; // 两个任务都调用完成，退出循环等待
                }
            }
            try {
                Map<String,String> url = task1.get();
                Map<String,String> status = task2.get();
                while(status==null||!status.get("instance_ip").contains("provider")){
                    status = openStackRestDao.getVirtualMachineStatus(username,password,virtualMachineName);
                }
                String instance_url = url.get("instance_url");
                String instance_ip = status.get("instance_ip");
                String instance_status=status.get("status");
                String instance_id = status.get("instance_id");
                vHostService.insertVhost(new Vhost(username,virtualMachineName,instance_id,image,cpu,ram,disk,
                        instance_ip,instance_url,currentTime,"false",instance_status));
                updateOpenStackUserCurrentQuota(username,true,"1",cpu,ram,disk);
                map.putAll(status);
                map.putAll(url);
                map.put("result","200");

            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    @Override
    public Map<String, String> getStatusAndUpdateDatabase(String username, String password, String hostId) {
        Map<String,String> map=new TreeMap<>();
        Map<String,String> temp =null;
        map.put("instance_id",hostId);
        map.put("event","getStatus");
        Vhost vhost=vHostService.selectVhostByHostId(hostId);
        if(vhost==null){
            map.put("result","数据库中找不到这台虚拟机");
            return map;
        }
        if((temp = openStackRestDao.getVirtualMachineStatus(username,password,hostId))!=null){
            vhost.setStatus(temp.get("status"));
            vhost.setIp(temp.get("instance_ip"));
            vHostService.updateVhost(hostId,vhost);
            map.put("result","200");
            map.putAll(temp);
            map.put("islocked",vhost.getIslocked());
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }
    @Override
    public Map<String,String> getUrlAndUpdateDatabase(String username, String password, String hostId) {
        Map<String,String> map=new TreeMap<>();
        Map<String,String> temp=null;
        map.put("instance_id",hostId);
        map.put("event","getUrl");
        Vhost vhost=vHostService.selectVhostByHostId(hostId);
        if(vhost==null){
            map.put("result","数据库中找不到这台虚拟机");
            return map;
        }
        if((temp = openStackRestDao.getVirtualMachineConsoleUrl(username,password,hostId))!=null){
            String instance_url =temp.get("instance_url");
            vhost.setUrl(instance_url);
            vHostService.updateVhost(hostId,vhost);
            map.put("result","200");
            map.put("instance_url",instance_url);
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> deleteVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map=new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","delete");
        Vhost vhost=vHostService.selectVhostByHostId(hostId);
        if(vhost==null){
            map.put("result","数据库中找不到这台虚拟机");
            return map;
        }
        if(!updateOpenStackUserCurrentQuota(username,false,"1",vhost.getCpu(),vhost.getRam(), vhost.getDisk())){
            map.put("result","你的配额为负的啦? what's the fuck !!!");
            return map;
        }
        if(openStackRestDao.deleteVirtualMachine(username,password,hostId)){
            vHostService.deleteVhostByHostId(hostId);
            map.put("result","200");
        }else {
            updateOpenStackUserCurrentQuota(username,true,"1",vhost.getCpu(),vhost.getRam(),vhost.getDisk());
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }
    @Override
    public Map<String,String> startVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        //首先告诉前台返回的是哪台虚拟机的操作结果
        map.put("instance_id",hostId);
        map.put("event","start");
        if(openStackRestDao.startVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"ACTIVE");
            map.put("result","200");//表明是启动操作，并且成功了
            map.put("status","ACTIVE");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> stopVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","stop");
        if(openStackRestDao.stopVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"SHUTDOWN");
            map.put("result","200");//表明是启动操作，并且成功了
            map.put("status","SHUTDOWN");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> rebootVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","reboot");
        if(openStackRestDao.rebootVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"ACTIVE");
            map.put("result","200");
            map.put("status","ACTIVE");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }
    @Override
    public Map<String,String> suspendVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","suspend");
        if(openStackRestDao.suspendVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"SUSPENDED");
            map.put("result","200");
            map.put("status","SUSPENDED");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> resumeVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","resume");
        if(openStackRestDao.resumeVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"ACTIVE");
            map.put("result","200");
            map.put("status","ACTIVE");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> pauseVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","pause");
        if(openStackRestDao.pauseVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"PAUSED");
            map.put("result","200");
            map.put("status","PAUSED");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> unpauseVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","unpause");
        if(openStackRestDao.unpauseVirtualMachine(username,password,hostId)){
            vHostService.updateVhostStatus(hostId,"ACTIVE");
            map.put("result","200");
            map.put("status","ACTIVE");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> lockVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","lock");
        if(openStackRestDao.lockVirtualMachine(username,password,hostId)){
            vHostService.updateVhostIsLocked(hostId,"true");
            map.put("result","200");
            map.put("islocked","true");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }

    @Override
    public Map<String,String> unlockVirtualMachine(String username, String password, String hostId) {
        Map<String,String> map =new TreeMap<>();
        map.put("instance_id",hostId);
        map.put("event","unlock");
        if(openStackRestDao.unlockVirtualMachine(username,password,hostId)){
            vHostService.updateVhostIsLocked(hostId,"false");
            map.put("result","200");
            map.put("islocked","false");
        }else {
            map.put("result","OpenStack错误,可能是服务器集群down机了");
        }
        return map;
    }
}
